#include "DXUT.h" // this include has to be included in the beginning of each source file for compiling

#include "./../Headers/init_win_dx.h"

//--------------------------------------------------------------------------------------
// Initialize the app 
//--------------------------------------------------------------------------------------
void InitApp() {

	// Initialize dialogs
	g_D3DSettingsDlg.Init( &g_DialogResourceManager );
	g_HUD.Init( &g_DialogResourceManager );
	g_SampleUI.Init( &g_DialogResourceManager );

	g_HUD.SetCallback( OnGUIEvent ); int iY = 20;
	g_HUD.AddButton( IDC_TOGGLEFULLSCREEN, L"Toggle full screen", 0, iY, 170, 22 );
	g_HUD.AddButton( IDC_TOGGLEREF, L"Toggle REF (F3)", 0, iY += 26, 170, 22, VK_F3 );
	g_HUD.AddButton( IDC_CHANGEDEVICE, L"Change device (F2)", 0, iY += 26, 170, 22, VK_F2 );

	g_SampleUI.SetCallback( OnGUIEvent ); iY = -20;

	WCHAR sz[100];
	swprintf_s( sz, L"Patch Divisions: %2.1f", g_fSubdivs );
	g_SampleUI.AddStatic( IDC_PATCH_SUBDIVS_STATIC, sz, 10, iY, 150, 22 );
	g_SampleUI.AddSlider( IDC_PATCH_SUBDIVS, 10, iY += 24, 150, 22, 10 * MIN_DIVS, 10 * MAX_DIVS, Round(g_fSubdivs * 10) );

	// Adding the ComboBox
	g_SampleUI.AddComboBox( IDC_SURFACE_SELECTION, 0, iY+=25, 150, 24, 'M', false, &g_pSurfaceSelectionCB );
	for( usint i = 0; i < g_iNumSurfaces; i++ ) {
		wchar_t wcstring[100];
		mbstowcs_s(NULL, wcstring, g_ParametricSurfaces[i].size()+1, g_ParametricSurfaces[i].c_str(), _TRUNCATE);
    
		g_pSurfaceSelectionCB->AddItem( wcstring, IntToPtr(i) );
	}

	g_pSurfaceSelectionCB->SetSelectedByIndex( 0 );
	g_pSurfaceSelectionCB->SetTextColor( D3DCOLOR_XRGB( 0, 0, 255 ) );

//	iY += 25;
	g_SampleUI.AddCheckBox( IDC_TOGGLE_LINES, L"Toggle Wires", 20, iY += 26, 150, 22, g_bDrawWires );

	g_SampleUI.AddRadioButton( IDC_PARTITION_INTEGER, IDC_PARTITION_MODE, L"Integer", 20, iY += 26, 170, 22 );
	g_SampleUI.AddRadioButton( IDC_PARTITION_FRAC_EVEN, IDC_PARTITION_MODE, L"Fractional Even", 20, iY += 26, 170, 22 );
	g_SampleUI.AddRadioButton( IDC_PARTITION_FRAC_ODD, IDC_PARTITION_MODE, L"Fractional Odd", 20, iY += 26, 170, 22 );
	g_SampleUI.GetRadioButton( IDC_PARTITION_INTEGER )->SetChecked( true );

	// Adding the time anim ComboBox
	g_SampleUI.AddComboBox( IDC_TIME_INTERPOL, 0, iY+=25, 150, 24, 'N', false, &ptrComboBox_time_interpol );

	{
		wchar_t wcstring[128];
		string name = "None";
		mbstowcs_s( NULL, wcstring, name.size()+1, name.c_str(), _TRUNCATE);
    
		ptrComboBox_time_interpol->AddItem( wcstring, IntToPtr(0) );

		name = "Linear";
		mbstowcs_s( NULL, wcstring, name.size()+1, name.c_str(), _TRUNCATE);
    
		ptrComboBox_time_interpol->AddItem( wcstring, IntToPtr(1) );

		name = "Quadratic";
		mbstowcs_s( NULL, wcstring, name.size()+1, name.c_str(), _TRUNCATE);
    
		ptrComboBox_time_interpol->AddItem( wcstring, IntToPtr(2) );

		name = "Cubic";
		mbstowcs_s( NULL, wcstring, name.size()+1, name.c_str(), _TRUNCATE);
    
		ptrComboBox_time_interpol->AddItem( wcstring, IntToPtr(3) );

		name = "Hermite";
		mbstowcs_s( NULL, wcstring, name.size()+1, name.c_str(), _TRUNCATE);
    
		ptrComboBox_time_interpol->AddItem( wcstring, IntToPtr(4) );

		ptrComboBox_time_interpol->SetSelectedByIndex( 0 );
	}

	// Adding the time anim ComboBox
	g_SampleUI.AddComboBox( IDC_TIME_ANIM, 0, iY+=25, 150, 24, 'N', false, &ptrComboBox_time_anim );

	{
		wchar_t wcstring[128];
		string name = "Still";
		mbstowcs_s( NULL, wcstring, name.size()+1, name.c_str(), _TRUNCATE);
    
		ptrComboBox_time_anim->AddItem( wcstring, IntToPtr(0) );

		name = "Forward";
		mbstowcs_s( NULL, wcstring, name.size()+1, name.c_str(), _TRUNCATE);
    
		ptrComboBox_time_anim->AddItem( wcstring, IntToPtr(1) );

		name = "Backward";
		mbstowcs_s( NULL, wcstring, name.size()+1, name.c_str(), _TRUNCATE);
    
		ptrComboBox_time_anim->AddItem( wcstring, IntToPtr(2) );

		ptrComboBox_time_anim->SetSelectedByIndex( 0 );
	}

	// time slider
	g_SampleUI.AddStatic( IDC_TIME_POSITION_STATIC_TEXT, L"", -350, iY -= 25, 150, 22 );
	g_SampleUI.AddSlider( IDC_TIME_POSITION, -350, iY += 25, 300, 22, Low(10 * time_initial), Low(10 * time_final), Low(10 * time_initial) );


	// Setup the camera's view parameters
	//D3DXVECTOR3 vecEye( -265.0, -240.0, 0.0f );
	//D3DXVECTOR3 vecAt ( -270.6502246, -248.2820741, 0.0f );
	D3DXVECTOR3 vecEye( -40.00, -60.0, 250.0f );
	D3DXVECTOR3 vecAt ( -47.00, -67.00, 256.00 );
	//D3DXVECTOR3 vecEye( 0.0, 0.0, -10.0 );
	//D3DXVECTOR3 vecAt ( 0.0, 0.0, 10.0 );
	g_Camera.SetViewParams( &vecEye, &vecAt );

};


//--------------------------------------------------------------------------------------
// Called right before creating a D3D9 or D3D10 device, allowing the app to modify the device settings as needed
//--------------------------------------------------------------------------------------
bool CALLBACK ModifyDeviceSettings( DXUTDeviceSettings* pDeviceSettings, void* pUserContext ) {

	// Disable vsync
	pDeviceSettings->d3d11.SyncInterval = 0;
	g_D3DSettingsDlg.GetDialogControl()->GetComboBox( DXUTSETTINGSDLG_PRESENT_INTERVAL )->SetEnabled( false );

	// For the first device created if its a REF device, optionally display a warning dialog box
	static bool s_bFirstTime = true;
	if( s_bFirstTime ) {
		s_bFirstTime = false;
		if(
			( DXUT_D3D9_DEVICE == pDeviceSettings->ver && pDeviceSettings->d3d9.DeviceType == D3DDEVTYPE_REF ) ||
			( DXUT_D3D11_DEVICE == pDeviceSettings->ver && pDeviceSettings->d3d11.DriverType == D3D_DRIVER_TYPE_REFERENCE )
		) {
			DXUTDisplaySwitchingToREFWarning( pDeviceSettings->ver );
		}
	}

	return true;
};


//--------------------------------------------------------------------------------------
// Handle updates to the scene
//--------------------------------------------------------------------------------------
void CALLBACK OnFrameMove( double fTime, float fElapsedTime, void* pUserContext ) {

	// Update the camera's position based on user input 
	g_Camera.FrameMove( fElapsedTime );
};


//--------------------------------------------------------------------------------------
// Render the help and statistics text
//--------------------------------------------------------------------------------------
void RenderText() {

	g_pTxtHelper->Begin();
	g_pTxtHelper->SetInsertionPos( 2, 0 );
	g_pTxtHelper->SetForegroundColor( D3DXCOLOR( 1.0f, 1.0f, 0.0f, 1.0f ) );
	g_pTxtHelper->DrawTextLine( DXUTGetFrameStats( DXUTIsVsyncEnabled() ) );
	g_pTxtHelper->DrawTextLine( DXUTGetDeviceStats() );

	g_pTxtHelper->End();

};


//--------------------------------------------------------------------------------------
// Handle messages to the application
//--------------------------------------------------------------------------------------
LRESULT CALLBACK MsgProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, bool* pbNoFurtherProcessing, void* pUserContext ) {

	// Pass messages to dialog resource manager calls so GUI state is updated correctly
	*pbNoFurtherProcessing = g_DialogResourceManager.MsgProc( hWnd, uMsg, wParam, lParam );
	if( *pbNoFurtherProcessing )
		return 0;

	// Pass messages to settings dialog if its active
	if( g_D3DSettingsDlg.IsActive() )
	{
		g_D3DSettingsDlg.MsgProc( hWnd, uMsg, wParam, lParam );
		return 0;
	}

	// Give the dialogs a chance to handle the message first
	*pbNoFurtherProcessing = g_HUD.MsgProc( hWnd, uMsg, wParam, lParam );
	if( *pbNoFurtherProcessing )
		return 0;
	*pbNoFurtherProcessing = g_SampleUI.MsgProc( hWnd, uMsg, wParam, lParam );
	if( *pbNoFurtherProcessing )
		return 0;

	// Pass all remaining windows messages to camera so it can respond to user input
	g_Camera.HandleMessages( hWnd, uMsg, wParam, lParam );

	return 0;
};

//--------------------------------------------------------------------------------------
// Handles the GUI events
//--------------------------------------------------------------------------------------
void CALLBACK OnGUIEvent( UINT nEvent, int nControlID, CDXUTControl* pControl, void* pUserContext ) {

	switch( nControlID ) {
			// Standard DXUT controls
		case IDC_TOGGLEFULLSCREEN:
			DXUTToggleFullScreen(); break;
		case IDC_TOGGLEREF:
			DXUTToggleREF(); break;
		case IDC_CHANGEDEVICE:
			g_D3DSettingsDlg.SetActive( !g_D3DSettingsDlg.IsActive() ); break;

			// Custom app controls
		case IDC_PATCH_SUBDIVS:
		{
			// Updating subdivision value
			g_fSubdivs = g_SampleUI.GetSlider( IDC_PATCH_SUBDIVS )->GetValue() / 10.0f;

			WCHAR sz[100];
			swprintf_s( sz, L"Patch Divisions: %2.1f", g_fSubdivs );
			g_SampleUI.GetStatic( IDC_PATCH_SUBDIVS_STATIC )->SetText( sz );
		}
			break;
			// Custom app controls
		case IDC_TIME_POSITION:
		{
			float time = g_SampleUI.GetSlider( IDC_TIME_POSITION )->GetValue() / 10.0f;
			// Updating subdivision value
			const_buf->setTimeValue( time - time_initial );
		}
			break;
		case IDC_TOGGLE_LINES:
			g_bDrawWires = g_SampleUI.GetCheckBox( IDC_TOGGLE_LINES )->GetChecked();
			break;
		case IDC_PARTITION_INTEGER:
			g_iPartitionMode = PARTITION_INTEGER;
			break;
		case IDC_PARTITION_FRAC_EVEN:
			g_iPartitionMode = PARTITION_FRACTIONAL_EVEN;
			break;
		case IDC_PARTITION_FRAC_ODD:
			g_iPartitionMode = PARTITION_FRACTIONAL_ODD;
			break;
		case IDC_TIME_ANIM:
			time_anim_type = PtrToInt( ptrComboBox_time_anim->GetSelectedData() );
			break;
		case IDC_TIME_INTERPOL:
			time_interpol_type = PtrToInt( ptrComboBox_time_interpol->GetSelectedData() );
			const_buf->getValue().iInterpolationType = time_interpol_type;
			break;
		case IDC_SURFACE_SELECTION: // The combo sets the index of the domain shader to be used
			CDXUTComboBox* pComboBox = ( CDXUTComboBox* )pControl;
			g_iCurrentSurface = PtrToInt( pComboBox->GetSelectedData() );
			break;
	}
};

//--------------------------------------------------------------------------------------
// Reject any D3D11 devices that aren't acceptable by returning false
//--------------------------------------------------------------------------------------
bool CALLBACK IsD3D11DeviceAcceptable( const CD3D11EnumAdapterInfo *AdapterInfo, UINT Output, const CD3D11EnumDeviceInfo *DeviceInfo,
										DXGI_FORMAT BackBufferFormat, bool bWindowed, void* pUserContext ) {
	return true;
};

//--------------------------------------------------------------------------------------
// Create any D3D11 resources that aren't dependant on the back buffer
//--------------------------------------------------------------------------------------
HRESULT CALLBACK OnD3D11CreateDevice( ID3D11Device* pd3dDevice, const DXGI_SURFACE_DESC* pBackBufferSurfaceDesc, void* pUserContext ) {

	// for macro using (V_RETURN)
	HRESULT hr;

	// Immediate Context
	ID3D11DeviceContext* pd3dImmediateContext = DXUTGetD3D11DeviceContext();
	V_RETURN( g_DialogResourceManager.OnD3D11CreateDevice( pd3dDevice, pd3dImmediateContext ) );
	V_RETURN( g_D3DSettingsDlg.OnD3D11CreateDevice( pd3dDevice ) );
	g_pTxtHelper = new CDXUTTextHelper( pd3dDevice, pd3dImmediateContext, &g_DialogResourceManager, 15 );

	// Compile shaders
	ID3DBlob* pBlobVS = NULL;
	ID3DBlob* pBlobHSInt = NULL;
	ID3DBlob* pBlobHSFracEven = NULL;
	ID3DBlob* pBlobHSFracOdd = NULL;
	// One blob for each domain shader
	std::vector<ID3DBlob*> blobDSArray;
	ID3DBlob* pBlobPS = NULL;
	ID3DBlob* pBlobPSSolid = NULL;

	// This macro is used to compile the hull shader with different partition modes
	// Please see the partitioning mode attribute for the hull shader for more information
	D3D10_SHADER_MACRO integerPartitioning[] = { { "HS_PARTITION", "\"integer\"" }, { 0 } };
	D3D10_SHADER_MACRO fracEvenPartitioning[] = { { "HS_PARTITION", "\"fractional_even\"" }, { 0 } };
	D3D10_SHADER_MACRO fracOddPartitioning[] = { { "HS_PARTITION", "\"fractional_odd\"" }, { 0 } };
	D3D10_SHADER_MACRO surfaceSettingMacro[] = { { 0 }, { 0 } };

	V_RETURN( CompileShaderFromFile( L"./Shaders/shader.hlsl", NULL,"VS", "vs_5_0",  &pBlobVS ) );
	V_RETURN( CompileShaderFromFile( L"./Shaders/shader.hlsl", integerPartitioning, "HS", "hs_5_0", &pBlobHSInt ) );
	V_RETURN( CompileShaderFromFile( L"./Shaders/shader.hlsl", fracEvenPartitioning, "HS", "hs_5_0", &pBlobHSFracEven ) );
	V_RETURN( CompileShaderFromFile( L"./Shaders/shader.hlsl", fracOddPartitioning, "HS", "hs_5_0", &pBlobHSFracOdd ) );
	// A separate binary of DS for every diferent define. Refer to the DS code in shader.hlsl
	for( usint i = 0; i < g_iNumSurfaces; i++ )
	{
		surfaceSettingMacro[0].Name = g_ParametricSurfaces[i].c_str();
		surfaceSettingMacro[0].Definition = "1";
		ID3DBlob* pBlobDS = NULL;
		V_RETURN( CompileShaderFromFile( L"./Shaders/shader.hlsl", surfaceSettingMacro, "DS", "ds_5_0", &pBlobDS ) );
		blobDSArray.push_back( pBlobDS );
	}

	V_RETURN( CompileShaderFromFile( L"./Shaders/shader.hlsl", NULL, "PS", "ps_5_0", &pBlobPS ) );
	V_RETURN( CompileShaderFromFile( L"./Shaders/shader.hlsl", NULL, "SolidColorPS", "ps_5_0", &pBlobPSSolid ) );

	// Create shaders
	V_RETURN( pd3dDevice->CreateVertexShader( pBlobVS->GetBufferPointer(), pBlobVS->GetBufferSize(), NULL, &g_pVertexShader ) );
	V_RETURN( pd3dDevice->CreateHullShader( pBlobHSInt->GetBufferPointer(), pBlobHSInt->GetBufferSize(), NULL, &g_pHullShaderInteger ) );
	V_RETURN( pd3dDevice->CreateHullShader( pBlobHSFracEven->GetBufferPointer(), pBlobHSFracEven->GetBufferSize(), NULL, &g_pHullShaderFracEven ) );
	V_RETURN( pd3dDevice->CreateHullShader( pBlobHSFracOdd->GetBufferPointer(), pBlobHSFracOdd->GetBufferSize(), NULL, &g_pHullShaderFracOdd ) );
	for( usint i = 0; i < g_iNumSurfaces; i++ ) {
		ID3D11DomainShader* currentDS;
		V_RETURN( pd3dDevice->CreateDomainShader( blobDSArray[i]->GetBufferPointer(), blobDSArray[i]->GetBufferSize(), NULL, &currentDS ) );
		g_DomainShaderArray.push_back( currentDS );
	}

	V_RETURN( pd3dDevice->CreatePixelShader( pBlobPS->GetBufferPointer(), pBlobPS->GetBufferSize(), NULL, &g_pPixelShader ) );
	V_RETURN( pd3dDevice->CreatePixelShader( pBlobPSSolid->GetBufferPointer(), pBlobPSSolid->GetBufferSize(), NULL, &g_pSolidColorPS ) );

	V_RETURN(
		pd3dDevice->CreateInputLayout( 
			control_point_layout, control_point_layout_size, pBlobVS->GetBufferPointer(),
			pBlobVS->GetBufferSize(), &g_control_point_layout
		)
	);

	SAFE_RELEASE( pBlobVS );
	SAFE_RELEASE( pBlobHSInt );
	SAFE_RELEASE( pBlobHSFracEven );
	SAFE_RELEASE( pBlobHSFracOdd );
	for( usint i = 0; i < g_iNumSurfaces; i++ )
		SAFE_RELEASE( blobDSArray[i] );
	SAFE_RELEASE( pBlobPS );
	SAFE_RELEASE( pBlobPSSolid );

	// Create solid and wireframe rasterizer state objects
	D3D11_RASTERIZER_DESC RasterDesc;
	ZeroMemory( &RasterDesc, sizeof(D3D11_RASTERIZER_DESC) );
	RasterDesc.FillMode = D3D11_FILL_SOLID;
	RasterDesc.CullMode = D3D11_CULL_NONE;
	RasterDesc.DepthClipEnable = TRUE;
	V_RETURN( pd3dDevice->CreateRasterizerState( &RasterDesc, &g_pRasterizerStateSolid ) );

	RasterDesc.FillMode = D3D11_FILL_WIREFRAME;
	V_RETURN( pd3dDevice->CreateRasterizerState( &RasterDesc, &g_pRasterizerStateWireframe ) );

	const_buf = new ConstantBuffer();
	tex_offset = new ShaderTexture();
	tex_pos = new ShaderTexture();

	/**!/
	AnflexUtil::readAnflexFile(
		"./Resources/Exemplo_02a_CrossSD"
	);
	// Setup the camera's view parameters
	D3DXVECTOR3 vecEye( -265.0, -240.0, 0.0f );
	D3DXVECTOR3 vecAt ( -270.6502246, -248.2820741, 0.0f );
	g_Camera.SetViewParams( &vecEye, &vecAt );
	/**/
	/**/
	AnflexUtil::readAnflexFile(
		"./Resources/Exemplo_01a_CrossSD"
	);
	// Setup the camera's view parameters
	D3DXVECTOR3 vecEye( -40.00, -60.0, 250.0f );
	D3DXVECTOR3 vecAt ( -47.00, -67.00, 256.00 );
	g_Camera.SetViewParams( &vecEye, &vecAt );
	/**/
	/**!/
	AnflexUtil::readAnflexFile(
		"./Resources/Entrada_Simples"
	);
	// Setup the camera's view parameters
	D3DXVECTOR3 vecEye( 0.0, 0.0, -10.0 );
	D3DXVECTOR3 vecAt ( 0.0, 0.0, 10.0 );
	g_Camera.SetViewParams( &vecEye, &vecAt );
	/**/


	/* defining the control points */
	//SIMPLE_CONTROL_POINT aux;
	//ZeroMemory( &aux, sizeof(SIMPLE_CONTROL_POINT) );
	//for( usint i = 0; i < qttPt; ++i ){
	//	aux.index = i;
	//	control_point_list, aux;
	//}

	/* creating buffer with the given points */
	D3D11_BUFFER_DESC vbDesc;
	ZeroMemory( &vbDesc, sizeof(D3D11_BUFFER_DESC) );
	vbDesc.ByteWidth = sizeof(SIMPLE_CONTROL_POINT) * control_point_list.size();
	vbDesc.Usage = D3D11_USAGE_DEFAULT;
	vbDesc.BindFlags = D3D11_BIND_VERTEX_BUFFER;

	D3D11_SUBRESOURCE_DATA vbInitData;
	ZeroMemory( &vbInitData, sizeof(vbInitData) );
	vbInitData.pSysMem = control_point_list.AsPointerArray();

	V_RETURN( pd3dDevice->CreateBuffer( &vbDesc, &vbInitData, &control_point_list_gpu ) );

	// Load the Texture
	//tex_offset = new ShaderTexture();
	//if( ! tex_offset->loadColorMatrix( "./Resources/entrada_02.txt" ) )
	//	throw Exception( "Couldn't read the texture!" );

	//MAT_COLOR_POS *matX = new MAT_COLOR_POS( 1, 2 );
	//COLOR_POS t_col;
	//t_col.pos[X] = 0.0; t_col.pos[Y] = 2.0; t_col.pos[Z] = 0.0;
	//matX->setVal( 0, 0, t_col );
	//t_col.pos[X] = 0.0; t_col.pos[Y] = -2.0; t_col.pos[Z] = 0.0;
	//matX->setVal( 0, 1, t_col );
	//tex_pos->setTexture( matX );
	if( !tex_offset->createOnDevice( pd3dDevice ) )
		throw Exception( "Couldn't map the texture to GPU." );

	if( !tex_pos->createOnDevice( pd3dDevice ) )
		throw Exception( "Couldn't map the texture to GPU." );

	//
	if( !tex_offset->saveToFile( pd3dImmediateContext, "test" ) )
		throw Exception( "Couldn't save the texture." );
	if( !tex_pos->saveToFile( pd3dImmediateContext, "test2" ) )
		throw Exception( "Couldn't save the texture." );


	// Create the sample state (linear)
	D3D11_SAMPLER_DESC sampDesc;
	ZeroMemory( &sampDesc, sizeof(sampDesc) );
	//sampDesc.Filter = D3D11_FILTER_MIN_MAG_MIP_POINT;
	sampDesc.Filter = D3D11_FILTER_MIN_MAG_LINEAR_MIP_POINT;
	sampDesc.AddressU = D3D11_TEXTURE_ADDRESS_BORDER;
	sampDesc.AddressV = D3D11_TEXTURE_ADDRESS_BORDER;
	sampDesc.AddressW = D3D11_TEXTURE_ADDRESS_BORDER;
	//sampDesc.ComparisonFunc = D3D11_COMPARISON_GREATER_EQUAL;
	sampDesc.ComparisonFunc = D3D11_COMPARISON_NEVER;
	sampDesc.MinLOD = 0;
	sampDesc.MaxLOD = 0;
	//sampDesc.MaxLOD = D3D11_FLOAT32_MAX;
	sampDesc.BorderColor[0] = 0.0;	sampDesc.BorderColor[1] = 0.0;	sampDesc.BorderColor[2] = 0.0;	sampDesc.BorderColor[3] = 0.0;
	V_RETURN( pd3dDevice->CreateSamplerState( &sampDesc, &sampler_linear ) );

	// Create the sample state (point)
	//D3D11_SAMPLER_DESC sampDesc;
	ZeroMemory( &sampDesc, sizeof(sampDesc) );
	sampDesc.Filter = D3D11_FILTER_MIN_MAG_MIP_POINT;
	//sampDesc.Filter = D3D11_FILTER_MIN_MAG_MIP_LINEAR;
	sampDesc.AddressU = D3D11_TEXTURE_ADDRESS_BORDER;
	sampDesc.AddressV = D3D11_TEXTURE_ADDRESS_BORDER;
	sampDesc.AddressW = D3D11_TEXTURE_ADDRESS_BORDER;
	//sampDesc.ComparisonFunc = D3D11_COMPARISON_GREATER_EQUAL;
	sampDesc.ComparisonFunc = D3D11_COMPARISON_NEVER;
	sampDesc.MinLOD = 0;
	sampDesc.MaxLOD = 0;
	//sampDesc.MaxLOD = D3D11_FLOAT32_MAX;
	sampDesc.BorderColor[0] = 0.0;	sampDesc.BorderColor[1] = 0.0;	sampDesc.BorderColor[2] = 0.0;	sampDesc.BorderColor[3] = 0.0;
	V_RETURN( pd3dDevice->CreateSamplerState( &sampDesc, &sampler_point ) );

	
	// Create constant buffers
	const_buf->startValue( tex_offset->getTexture()->w, tex_offset->getTexture()->h, g_Camera );
	if( ! const_buf->createOnDevice( pd3dDevice ) )
		throw Exception( "Couldn't crete the constant buffer on the given device." );

	// updating time slider
	const_buf->setSliderTimer( g_SampleUI.GetSlider( IDC_TIME_POSITION ), g_SampleUI.GetStatic( IDC_TIME_POSITION_STATIC_TEXT ) );
	g_SampleUI.GetSlider( IDC_TIME_POSITION )->SetRange( Low(10 * time_initial), Low(10 * time_final) );
	g_SampleUI.GetSlider( IDC_TIME_POSITION )->SetValue( Low(10 * time_initial) );

	WCHAR sz[100];
	swprintf_s( sz, L"Time: %2.1f", time_initial );
	g_SampleUI.GetStatic( IDC_TIME_POSITION_STATIC_TEXT )->SetText( sz );

	return S_OK;
};

//--------------------------------------------------------------------------------------
// Create any D3D11 resources that depend on the back buffer
//--------------------------------------------------------------------------------------
HRESULT CALLBACK OnD3D11ResizedSwapChain( ID3D11Device* pd3dDevice, IDXGISwapChain* pSwapChain,
											const DXGI_SURFACE_DESC* pBackBufferSurfaceDesc, void* pUserContext ) {

	HRESULT hr;

	V_RETURN( g_DialogResourceManager.OnD3D11ResizedSwapChain( pd3dDevice, pBackBufferSurfaceDesc ) );
	V_RETURN( g_D3DSettingsDlg.OnD3D11ResizedSwapChain( pd3dDevice, pBackBufferSurfaceDesc ) );

	// Setup the camera's projection parameters
	float fAspectRatio = pBackBufferSurfaceDesc->Width / ( FLOAT )pBackBufferSurfaceDesc->Height;
	g_Camera.SetProjParams( D3DX_PI / 4, fAspectRatio, 0.1f, 10000.0f );
	g_Camera.SetWindow( pBackBufferSurfaceDesc->Width, pBackBufferSurfaceDesc->Height );
	g_Camera.SetButtonMasks( MOUSE_WHEEL, MOUSE_RIGHT_BUTTON, MOUSE_LEFT_BUTTON );
//	g_Camera.SetButtonMasks( MOUSE_MIDDLE_BUTTON, MOUSE_WHEEL, MOUSE_LEFT_BUTTON );

	g_HUD.SetLocation( pBackBufferSurfaceDesc->Width - 170, 0 );
	g_HUD.SetSize( 170, 170 );
	g_SampleUI.SetLocation( pBackBufferSurfaceDesc->Width - 170, pBackBufferSurfaceDesc->Height - 300 );
	g_SampleUI.SetSize( 170, 300 );

	return S_OK;
};

//--------------------------------------------------------------------------------------
// Render the scene using the D3D11 device
// ftime - tempo total decorrido desde o inicio
// fElapsedTime - tempo decorrido desde a ultima atualizacao
//--------------------------------------------------------------------------------------
void CALLBACK OnD3D11FrameRender( ID3D11Device* pd3dDevice, ID3D11DeviceContext* pd3dImmediateContext, double fTime, float fElapsedTime, void* pUserContext ) {

	// If the settings dialog is being shown, then render it instead of rendering the app's scene
	if( g_D3DSettingsDlg.IsActive() ) {
		g_D3DSettingsDlg.OnRender( fElapsedTime );
		return;
	}

	// update - constant buffer
//	const_buf->updateValue( g_Camera, fElapsedTime, g_fSubdivs );
	if( time_anim_type == 0 ) {
		const_buf->updateValue( g_Camera, 0.0, g_fSubdivs );
	}
	else if( time_anim_type == 1 ) {
		const_buf->updateValue( g_Camera, fElapsedTime/10.0, g_fSubdivs );
	}
	else if( time_anim_type == 2 ) {
		const_buf->updateValue( g_Camera, -fElapsedTime/10.0, g_fSubdivs );
	}
	const_buf->updateOnDeviceContext( pd3dImmediateContext );

	// Clear the render target and depth stencil
	float ClearColor[4] = { 0.00f, 0.0f, 0.0f, 0.0f };
	ID3D11RenderTargetView* pRTV = DXUTGetD3D11RenderTargetView();
	pd3dImmediateContext->ClearRenderTargetView( pRTV, ClearColor );
	ID3D11DepthStencilView* pDSV = DXUTGetD3D11DepthStencilView();
	pd3dImmediateContext->ClearDepthStencilView( pDSV, D3D11_CLEAR_DEPTH, 1.0, 0 );

	// Set state for solid rendering
	pd3dImmediateContext->RSSetState( g_pRasterizerStateSolid );

	// Render the meshes

	// Bind all of the CBs
	pd3dImmediateContext->VSSetConstantBuffers( 0, 1, &( const_buf->getBufferGPU() ) );
	pd3dImmediateContext->HSSetConstantBuffers( 0, 1, &( const_buf->getBufferGPU() ) );
	pd3dImmediateContext->DSSetConstantBuffers( 0, 1, &( const_buf->getBufferGPU() ) );
	pd3dImmediateContext->PSSetConstantBuffers( 0, 1, &( const_buf->getBufferGPU() ) );

	// Set the shaders
	// - Vertex
	pd3dImmediateContext->VSSetShader( g_pVertexShader, NULL, 0 );

	// - Hull
	// For this sample, choose either the "integer", "fractional_even", or "fractional_odd" hull shader
	if (g_iPartitionMode == PARTITION_INTEGER)
		pd3dImmediateContext->HSSetShader( g_pHullShaderInteger, NULL, 0 );
	else if (g_iPartitionMode == PARTITION_FRACTIONAL_EVEN)
		pd3dImmediateContext->HSSetShader( g_pHullShaderFracEven, NULL, 0 );
	else if (g_iPartitionMode == PARTITION_FRACTIONAL_ODD)
		pd3dImmediateContext->HSSetShader( g_pHullShaderFracOdd, NULL, 0 );

	// - Domain
	pd3dImmediateContext->DSSetShader( g_DomainShaderArray[g_iCurrentSurface], NULL, 0 );
	// - Geometry
	pd3dImmediateContext->GSSetShader( NULL, NULL, 0 );
	// - Pixel
	pd3dImmediateContext->PSSetShader( g_pPixelShader, NULL, 0 );

	// Optionally draw the wireframe
	if( g_bDrawWires ) {
		pd3dImmediateContext->PSSetShader( g_pSolidColorPS, NULL, 0 );
		pd3dImmediateContext->RSSetState( g_pRasterizerStateWireframe );
	}

	// Set the input assembler
	// This Sample uses only one control point ( just to enable the pipeline )
	pd3dImmediateContext->IASetInputLayout( g_control_point_layout );
	UINT Stride = sizeof( SIMPLE_CONTROL_POINT );
	UINT Offset = 0;
	pd3dImmediateContext->IASetVertexBuffers( 0, 1, &control_point_list_gpu, &Stride, &Offset );
	// must match with patch size in the hlsl file
	pd3dImmediateContext->IASetPrimitiveTopology( D3D11_PRIMITIVE_TOPOLOGY::D3D11_PRIMITIVE_TOPOLOGY_1_CONTROL_POINT_PATCHLIST );

	ID3D11ShaderResourceView *tex_list[2];
	tex_list[0] = tex_offset->getTextureGPU();
	tex_list[1] = tex_pos->getTextureGPU();

	pd3dImmediateContext->VSSetShaderResources( g_iBindPerFrame, 2, tex_list );
	pd3dImmediateContext->PSSetShaderResources( g_iBindPerFrame, 2, tex_list );

	ID3D11SamplerState *samp_list[2];
	samp_list[0] = sampler_linear;
	samp_list[1] = sampler_point;

	pd3dImmediateContext->VSSetSamplers( g_iBindPerFrame, 2, samp_list );
	pd3dImmediateContext->PSSetSamplers( g_iBindPerFrame, 2, samp_list );

	// Draw the mesh
	pd3dImmediateContext->Draw( control_point_list.size(), 0 );

	pd3dImmediateContext->RSSetState( g_pRasterizerStateSolid );

	// Render the HUD
	DXUT_BeginPerfEvent( DXUT_PERFEVENTCOLOR, L"HUD / Stats" );
	g_HUD.OnRender( fElapsedTime );
	g_SampleUI.OnRender( fElapsedTime );
	RenderText();
	DXUT_EndPerfEvent();

};

//--------------------------------------------------------------------------------------
// Release D3D11 resources created in OnD3D10ResizedSwapChain 
//--------------------------------------------------------------------------------------
void CALLBACK OnD3D11ReleasingSwapChain( void* pUserContext ) {
	g_DialogResourceManager.OnD3D11ReleasingSwapChain();
};

void EndShaders();

//--------------------------------------------------------------------------------------
// Release D3D11 resources created in OnD3D10CreateDevice 
//--------------------------------------------------------------------------------------
void CALLBACK OnD3D11DestroyDevice( void* pUserContext ) {

	g_DialogResourceManager.OnD3D11DestroyDevice();
	g_D3DSettingsDlg.OnD3D11DestroyDevice();
	DXUTGetGlobalResourceCache().OnDestroyDevice();
	SAFE_DELETE( g_pTxtHelper );
	SAFE_RELEASE( g_control_point_layout );

	EndShaders();

};

void EndShaders(){

	SAFE_RELEASE( g_pVertexShader );
	SAFE_RELEASE( g_pHullShaderInteger );
	SAFE_RELEASE( g_pHullShaderFracEven );
	SAFE_RELEASE( g_pHullShaderFracOdd );
	for( usint i = 0; i < g_iNumSurfaces; i++ )
		SAFE_RELEASE( g_DomainShaderArray[i] );
	SAFE_RELEASE( g_pPixelShader );
	SAFE_RELEASE( g_pSolidColorPS );

	SAFE_RELEASE( g_pRasterizerStateSolid );
	SAFE_RELEASE( g_pRasterizerStateWireframe );

	SAFE_RELEASE( control_point_list_gpu );
	control_point_list.empty();

	SafeDelete( const_buf );
	SafeDelete( tex_offset );
	SAFE_RELEASE( sampler_linear );
	SafeDelete( tex_pos );
	SAFE_RELEASE( sampler_point );

};
